/**
 * Copyright (C) 2017 - 2020 https://github.com/joewee
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bifrost.web.controller;

import com.alibaba.fastjson.JSON;
import com.bifrost.annotation.Authorization;
import com.bifrost.annotation.CurrentStore;
import com.bifrost.annotation.CurrentUser;
import com.bifrost.common.model.ResultModel;
import com.bifrost.constant.OrderStatusHistoryOrderType;
import com.bifrost.constant.OrderType;
import com.bifrost.constant.ShippingType;
import com.bifrost.entity.*;
import com.bifrost.exception.*;
import com.bifrost.model.*;
import com.bifrost.service.*;
import com.bifrost.util.TransformUtils;
import com.bifrost.wrapper.CouponWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单相关api接口
 *
 * @author joewee
 * @version 1.0.0
 * @Date 2017/11/2 17:36
 */
@RestController
@Api("订单相关接口")
@RequestMapping("/api/order")
public class OrderController {
    private static final Logger LOGGER = LoggerFactory.getLogger(OrderController.class);

    @Autowired
    PaymentService paymentService;
    @Autowired
    CustomerService customerService;
    @Autowired
    CouponService couponService;
    @Autowired
    PricingService pricingService;
    @Autowired
    OrderService orderService;
    @Autowired
    ShippingService shippingService;
    @Autowired
    StoreService storeService;
    @Autowired
    AdminUserService userService;

    @Authorization
    @ApiOperation("获取基本信息（默认地址、支付方式）")
    @GetMapping("/defaultInfo")
    public ResultModel getDefaultInfo(@CurrentUser Long userId) {
        Customer user = customerService.findCustomer(userId);
        CustomerAddress address = customerService.getCustomerDefaultAddress(user);
        List<Payment> payments = paymentService.getAllPayments();
        ResultModel model = new ResultModel();
        if (null != address) {
            Map map = new HashMap(10);
            map.put("addressId", address.getCustomerAddressId());
            map.put("addressState", address.getAddressState().getId());
            map.put("addressStateName", address.getAddressState().getName());
            map.put("addressCity", address.getAddressCity().getId());
            map.put("addressCityName", address.getAddressCity().getName());
            map.put("addressDistrict", address.getAddressDistrict().getId());
            map.put("addressDistrictName", address.getAddressDistrict().getName());
            map.put("addressStreet", address.getAddressStreet());
            map.put("phonePrimary", address.getPhonePrimary());
            map.put("lastName", address.getLastName());
            model.put("address", map);
        }
        if (!payments.isEmpty()) {
            List<Map> paymentsList = new ArrayList<>(payments.size());
            payments.forEach(payment -> {
                Map payMap = new HashMap();
                payMap.put("id", payment.getPaymentTypeId());
                payMap.put("description", payment.getDescription());
                paymentsList.add(payMap);
            });
            model.put("payments", paymentsList);
        }
        model.put("customerPhoneNumber", user.getCustomerPhone());
        model.put("bonusPoints", user.getBonusPoints());
        return model;
    }

    @Authorization
    @ApiOperation("获取会员所有收货地址")
    @GetMapping("/addressList")
    public ResultModel getAllAddress(@CurrentUser Long userId) {
        Customer user = customerService.findCustomer(userId);
        List<CustomerAddress> addresses = customerService.getAllAddress(user);
        List<Map> addressList = new ArrayList<>(addresses.size());
        addresses.forEach(address -> {
            Map map = new HashMap(10);
            map.put("addressId", address.getCustomerAddressId());
            map.put("addressState", address.getAddressState().getId());
            map.put("addressStateName", address.getAddressState().getName());
            map.put("addressCity", address.getAddressCity().getId());
            map.put("addressCityName", address.getAddressCity().getName());
            map.put("addressDistrict", address.getAddressDistrict().getId());
            map.put("addressDistrictName", address.getAddressDistrict().getName());
            map.put("addressStreet", address.getAddressStreet());
            map.put("phonePrimary", address.getPhonePrimary());
            map.put("lastName", address.getLastName());
            map.put("default", 0);
            addressList.add(map);
        });
        if (!addressList.isEmpty()) {
            addressList.get(0).put("default", 1);
        }
        return ResultModel.ok().put("address", addressList);
    }

    @Authorization
    @ApiOperation("订单页面获取可用优惠券")
    @ApiImplicitParam(paramType = "query", name = "data", dataType = "String", value = "订单数据（json）", required = true)
    @PostMapping("/coupons")
    public ResultModel getCoupons(@CurrentUser Long userId, String data) throws PricingException {
        // TODO 减少流量请求  --线上优惠券暂时未开通
        if(1>0) {
            return ResultModel.ok().put("count", 0).put("availableCount", 0);
        }
        Customer user = customerService.findCustomer(userId);
        OrderRequest request = JSON.parseObject(data, OrderRequest.class);
        if (!orderService.isValidRequest(request)) {
            return ResultModel.error("无效的订单");
        }
        Order order = orderService.newOrder(request, user);
        order.setShippingType(ShippingType.SELF_DELIVERY);
        /**计算应付金额
         * 1、确认订单信息
         * 2、查询优惠券
         * */
        try {
            orderService.getConfirmOrderData(order);
        } catch (UnsupportedShippingTypeException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (PromotionException e) {
            LOGGER.error(e.getMessage(), e);
        }catch (ProductUnavaliableException e){
            LOGGER.error(e.getErrorMsg(), e);
            return ResultModel.error("商品不可销售");
        }
        List<CouponWrapper> list = couponService.getCoupons(order);
        if (list == null || list.isEmpty()) {
            return ResultModel.ok().put("count", 0).put("availableCount", 0);
        }
        ResultModel resultModel = new ResultModel();
        List<CouponModel> availableList = new ArrayList<>(list.size());
        List<CouponModel> unavailableList = new ArrayList<>(list.size());
        list.forEach(couponWrapper -> {
            if (couponWrapper.isAvailable()) {
                CouponModel model = TransformUtils.transformToCouponModel(couponWrapper.getDetail());
                model.setAvailable(true);
                model.setExpiration(false);
                availableList.add(model);
            } else {
                CouponModel model = TransformUtils.transformToCouponModel(couponWrapper.getDetail());
                model.setAvailable(false);
                model.setUnavailableReason(couponWrapper.getUnavailableReason());
                unavailableList.add(model);
            }
        });
        return resultModel.put("unavailable", unavailableList).put("available", availableList).put("count", list.size()).put("availableCount", availableList.size());
    }

    @Authorization
    @ApiOperation("确认订单信息")
    @ApiImplicitParam(paramType = "query", name = "data", dataType = "String", value = "订单数据（json）", required = true)
    @PostMapping("/confirm")
    public ResultModel confirmOrder(@CurrentUser Long userId, @RequestParam String data) {
        OrderRequest request = null;
        try {
            request = JSON.parseObject(data, OrderRequest.class);
        } catch (Exception e) {
            return ResultModel.error("无效的订单");
        }
        if (!orderService.isValidRequest(request)) {
            return ResultModel.error("无效的订单");
        }
        String orderType = request.getOrderType();
        MerchantStore store = orderService.allInOneStore(request);
        if (store == null) {
            return ResultModel.error("订单中的商品属于不同店铺不能合并下单");
        }
        //需要服务且服务门店不为空时验证门店是否提供服务
        /*if (request.isNeedService() && request.getServiceShop() != null && !storeService.canService(request)) {
            return ResultModel.error("所选门店不能提供订单所需的所有服务请更换其他门店");
        }*/
        //需要快递配送时验证快递是否到达
        if (ShippingType.DELIVERY.equalsIgnoreCase(request.getShippingType())) {
            if(request.getDistrict() != null && !shippingService.canDelivery(request)){
                return ResultModel.error("所选区域快递不配送");
            }
        }
        Customer user = customerService.findCustomer(userId);
        Order order = orderService.newOrder(request, user);
        order.setMerchantStore(store);
        //团购订单
        if (OrderType.GROUPON.equalsIgnoreCase(orderType)) {
            order.setOrderType(OrderType.GROUPON);
        }//积分兑换
        else if (OrderType.EXCHANGE.equalsIgnoreCase(orderType)) {
            order.setOrderType(OrderType.EXCHANGE);
        }//秒杀
        else if (OrderType.SECKILL.equalsIgnoreCase(orderType)) {
            order.setOrderType(OrderType.SECKILL);
        }
        else if (OrderType.GENERAL.equalsIgnoreCase(orderType)) {
            order.setOrderType(OrderType.GENERAL);
        }
        else {
            return ResultModel.error("不支持的订单类型");
        }
        //计价
        String shippingOptions=null;
        try {
            orderService.getConfirmOrderData(order);
            shippingOptions= order.getShippingOptions();
            pricingService.executePricing(order);
        } catch (PricingException e) {
            LOGGER.error(e.getMessage(), e);
            return ResultModel.error("确认订单信息失败");
        } catch (UnsupportedShippingTypeException e) {
            LOGGER.error(e.getMessage(), e);
            return ResultModel.error("订单不能合并付款，存在不兼容快递类型");
        } catch (PromotionException e) {
            LOGGER.error(e.getMessage(), e);
            return ResultModel.error("订单包含的促销活动未开始或已结束");
        }catch (ProductUnavaliableException e){
            LOGGER.error(e.getErrorMsg(), e);
            return ResultModel.error("商品不可销售");
        }

        OrderModel orderModel = orderService.convertToOrderModel(order);
        orderModel.setCartId(request.getCartId());
        return ResultModel.ok("成功").put("orderData", orderModel).put("shippingOptions",shippingOptions);
    }

    @Authorization
    @ApiOperation("获取所有订单")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "page", value = "当前页", required = false, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "pageSize", value = "每页数量", required = false, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "status", value = "订单状态", required = true, dataType = "String"),
    })
    @GetMapping("/orders")
    public ResultModel orders(@CurrentStore Long storeId, @CurrentUser Long userId, @RequestParam String status, @RequestParam(value = "page", defaultValue = "1") String page,
                              @RequestParam(value = "pageSize", defaultValue = "10") String pageSize) {
        if ("ALL".equalsIgnoreCase(status)) {
            status = "";
        }
        Customer customer = customerService.findCustomer(userId);
        List<OrderResult> orders = orderService.getOrders(Integer.parseInt(page), Integer.parseInt(pageSize), customer, customer.getMerchantStore(), status, false);
        return ResultModel.ok().put("orders", orders);
    }

    @Authorization
    @ApiOperation("获取所有待评价订单")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "page", value = "当前页", required = false, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "pageSize", value = "每页数量", required = false, dataType = "String"),
    })
    @GetMapping("/orders/nocomment")
    public ResultModel getNotCommentorders(@CurrentStore Long storeId, @CurrentUser Long userId, @RequestParam(value = "page", defaultValue = "1") String page,
                              @RequestParam(value = "pageSize", defaultValue = "10") String pageSize) {
        Customer user = customerService.findCustomer(userId);
        List<OrderResult> orders = orderService.getOrders(Integer.parseInt(page), Integer.parseInt(pageSize), user, user.getMerchantStore(),  null,true);
        return ResultModel.ok().put("orders", orders);
    }

    @Authorization
    @ApiOperation("订单详情(非退货)")
    @ApiImplicitParam(paramType = "query", name = "orderId", value = "订单id", required = true, dataType = "Long")
    @GetMapping("/order")
    public ResultModel order(@RequestParam Long orderId) {
        Order order = orderService.findOrderById(orderId);
        Map result = orderService.orderDetails(order);
        return ResultModel.ok(result);
    }

    @Authorization
    @ApiOperation("获取不同状态订单数量")
    @GetMapping("/status")
    public ResultModel order(@CurrentStore Long storeId, @CurrentUser Long userId) {
        Customer customer = customerService.findCustomer(userId);
        Map map = orderService.countStatus(customer, customer.getMerchantStore());
        return ResultModel.ok().put("status", map);
    }

    @Authorization
    @ApiOperation("取消订单")
    @ApiImplicitParam(paramType = "query", name = "orderId", value = "订单Id", required = true, dataType = "Long")
    @PostMapping("/cancel")
    public ResultModel cancel(@CurrentUser Long userId, @RequestParam Long orderId) {
        try {
            Customer customer = customerService.findCustomer(userId);
            orderService.cancel(customer, orderId, "由用户取消");
            return ResultModel.ok("已成功取消订单");
        } catch (CancelOrderException e) {
            LOGGER.error(e.getMessage(),e);
        }
        return ResultModel.error("取消订单失败");
    }

    @ApiOperation("查询所有门店")
    @PostMapping("/serviceShops")
    public ResultModel getStores(@RequestParam String data) {
        OrderRequest request = null;
        try {
            request = JSON.parseObject(data, OrderRequest.class);
        } catch (Exception e) {
            return ResultModel.error("无效的订单");
        }
        String orderType = request.getOrderType();
        if (StringUtils.isEmpty(orderType)) {
            return ResultModel.error("无效的订单类型");
        }
        if (!orderService.isValidRequest(request)) {
            return ResultModel.error("无效的订单");
        }
        List<MerchantStore> stores = orderService.getStores(request);
        if (stores.isEmpty()) {
            return ResultModel.error("未找到数据");
        }
        List<StoreModel> models = new ArrayList<>(stores.size());
        List<AreaModel> areas = new ArrayList<>(stores.size());
        stores.forEach(merchantStore -> {
            CountryArea countryArea = merchantStore.getStoreDistrict();
            AreaModel info = new AreaModel(countryArea.getId(), countryArea.getName());
            areas.add(info);
            models.add(TransformUtils.transformToStoreModel(merchantStore));
        });
        //去重
        List<AreaModel> distinctAreas = areas.stream().distinct().collect(Collectors.toList());
        return ResultModel.ok("成功").put("areas", distinctAreas).put("stores", models);
    }

    @Authorization
    @ApiOperation("确认收货")
    @ApiImplicitParam(paramType = "query", name = "orderId", value = "订单Id", required = true, dataType = "Long")
    @PostMapping("/received")
    public ResultModel confirmReceive(@CurrentUser Long userId, Long orderId,String code) {
        Customer user = customerService.findCustomer(userId);
        return orderService.confirmReceived(user, orderId,code);
    }

    @Authorization
    @ApiOperation("提货码验证")
    @ApiImplicitParam(paramType = "query", name = "code", value = "订单提货码", required = true, dataType = "String")
    @PostMapping("/checkoutCode")
    public ResultModel confirmCode( @RequestParam("orderId")Long orderId , @RequestParam("code") String code) {
        User user;
        Assert.notNull(user = userService.findUserByCode(code),"请检验提货码");
        Order order = orderService.findOrderById(orderId);
        Assert.isTrue(user.getMerchantStores().stream().filter(store -> {
            return store.getMerchantId().equals(order.getMerchantStore().getMerchantId());
        }).count()>0,"请检验提货码");

        return ResultModel.ok().put("data",true);
    }

    @ApiOperation("获取订单状态记录")
    @GetMapping("/histories")
    @Authorization
    public ResultModel getStatusHistories(@CurrentUser Long userId, @RequestParam Long orderId) {
        Customer customer = customerService.findCustomer(userId);
        Order order = orderService.findOrderByIdAndCustomer(orderId, customer);
        if (order != null) {
            List<OrderStatusHistory> histories = order.getOrderStatusHistories();
            if (CollectionUtils.isNotEmpty(histories)) {
                List<OrderStatusHistoryModel> models = new ArrayList<>(histories.size());
                List<OrderStatusHistory> list =histories.stream().filter(history -> {
                    return OrderStatusHistoryOrderType.ORDER.equalsIgnoreCase(history.getOrderType());
                }).sorted(new Comparator<OrderStatusHistory>() {
                    @Override
                    public int compare(OrderStatusHistory o1, OrderStatusHistory o2) {
                        return o2.getOrderStatusHistoryId().compareTo(o1.getOrderStatusHistoryId());
                    }
                }).collect(Collectors.toList());
                list.forEach(history -> {
                    models.add(TransformUtils.transformToOrderStatusHistoryModel(history));
                });
                return ResultModel.ok().put("histories", models);
            }
            return ResultModel.ok();
        }
        return ResultModel.error("未找到对应的订单记录");
    }
}